package xyz.heyaoshare.config.websocket.chat;

import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import xyz.heyaoshare.config.websocket.manager.WebSocketSessionManager;

import java.io.IOException;
import java.util.Map;

/**
 * WebSocket Chat 处理器
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 下午1:34
 */
@Slf4j
@Component
public class ChatSocketHandler extends TextWebSocketHandler {


    // 单例模式
    final WebSocketSessionManager instance = WebSocketSessionManager.getInstance();

    /**
     * 当WebSocket连接建立后被调用。
     * <p>
     * 此方法处理WebSocket连接的建立逻辑。首先，它记录了一条新连接建立的日志。
     * 然后，它尝试从会话属性中获取用户ID。如果用户ID不存在，将关闭连接并记录警告日志。
     * 如果用户ID已存在但对应的会话也已存在，同样会关闭新连接并记录警告日志，表示不允许重复连接。
     * 如果用户ID有效且未与其他会话关联，则将其注册为新会话，并记录连接成功和当前会话数量的日志。
     *
     * @param session WebSocket会话对象，包含客户端的连接信息。
     * @throws IOException 如果在处理连接时出现输入输出异常。
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws IOException {
        log.info("【WebSocket】有一个新连接!");
        Map<String, Object> attributes = session.getAttributes();
        Object object = attributes.get("userId");


        // 用户ID不存在，关闭连接并记录日志
        String sessionId = session.getId();
        if (object == null) {
            log.warn("【WebSocket】连接缺少userId，关闭连接: {}", sessionId);
            session.close(CloseStatus.NOT_ACCEPTABLE);
            return;
        }

        String userId = object.toString();
        WebSocketSession existingSession = instance.getSession(userId);
        // 判断用户ID是否已存在，存在则关闭新连接并记录日志
        if (existingSession != null) {
            log.warn("【WebSocket】用户ID {} 已连接，关闭重复连接: {}", userId, sessionId);
            session.close(CloseStatus.GOING_AWAY);
            return;
        }

        instance.registerSession(userId, session);
        log.info("【WebSocket】userId: {} 已连接!session：{}", object, sessionId);
        log.info("【WebSocket】当前连接数: {}", instance.size());
    }

    /**
     * 处理客户端发送的文本消息。
     * <p>
     * 此方法重写了父类的方法，用于处理WebSocket客户端发送的文本消息。
     * 当接收到客户端发送的文本消息时，首先记录日志信息，包括消息内容和会话ID。
     * 然后，向客户端发送一个回显消息，消息内容为“Echo: ”加上客户端发送的原始消息内容。
     *
     * @param session WebSocket会话对象，表示当前与客户端的连接。
     * @param message 客户端发送的文本消息。
     * @throws Exception 如果在处理消息过程中发生异常，则抛出此异常。
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("【WebSocket】收到来自 {} 的消息: {}", session.getId(), message.getPayload());
    }

    /**
     * WebSocket连接关闭后的处理方法。
     * <p>
     * 当WebSocket连接关闭时，此方法会被调用。
     * 在这里，我们记录了一条日志，记录了会话ID和连接关闭的状态，
     * 并在连接关闭后从会话管理器中移除对应的会话。
     *
     * @param session WebSocket会话对象，包含了会话的详细信息。
     * @param status  连接关闭的状态，不能为null。
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, @NotNull CloseStatus status) {
        log.info("【WebSocket】已断开连接! session: {} 状态 {}", session.getId(), status);
        instance.removeBySession(session.getId());
        log.info("【WebSocket】当前连接数: {}", instance.size());
    }

}